package com.zhome.gateway.filter.pre;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.zhome.gateway.constants.Constants;
import com.zhome.gateway.dto.ZhomeRouteDto;
import com.zhome.gateway.enums.FilterEnum;
import com.zhome.gateway.enums.GateWayCodeEnum;
import com.zhome.gateway.enums.ZhomeHttpEnum;
import com.zhome.gateway.filter.AbstractZhomeZuulFilter;
import com.zhome.gateway.response.TokenValidResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StreamUtils;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;

/**
 * 验证Token，也就是接口需要登录访问
 * @author cuiyh9
 * @date 2020/5/9
 */
@Slf4j
public class TokenValidateFilter extends AbstractZhomeZuulFilter {

    private CloseableHttpClient httpClient;

    @Value("${token.valid.url}")
    private String tokenValidUrl;

    @PostConstruct
    private void initialize() {
        httpClient = buildHttpClient();
    }

    @Override
    public String filterType() {
        return Constants.PRE_KEY;
    }

    @Override
    public int filterOrder() {
        return FilterEnum.TokenValidateFilterEnum.getFilterOrder();
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return ctx.getBoolean(Constants.RequestContextKey.CTX_X_SUCCESSOR_CAN_EXECUTE);
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        if (isNotNeedValidToken(ctx)) {
            return null;
        }

        HttpGet httpGet = buildHttpGet(ctx);
        try {
            HttpResponse httpResponse = httpClient.execute(httpGet);
            if (ZhomeHttpEnum.isNotSuccessCode(httpResponse.getStatusLine().getStatusCode())) {
                setSkipToPostTypeFilter(ctx);
                setFailResponse(GateWayCodeEnum.TOKEN_VALID_FAIL);
                return null;
            }
            HttpEntity httpEntity = httpResponse.getEntity();
            String tokenValidStringRes = StreamUtils.copyToString(httpEntity.getContent(), StandardCharsets.UTF_8);
            ObjectMapper mapper = new ObjectMapper();
            TokenValidResponse  tokenValidResponse = mapper.readValue(tokenValidStringRes, TokenValidResponse.class);
            // 此处人isNotSuccessCode和上面的是两个不同的含业
            if (ZhomeHttpEnum.isNotSuccessCode(tokenValidResponse.getCode())) {
                setSkipToPostTypeFilter(ctx);
                setFailResponse(GateWayCodeEnum.TOKEN_VALID_FAIL);
            }
        } catch (IOException e) {
            log.error("TokenValidateFilter error!RequestId:%s", requestId(), e);
            setSkipToPostTypeFilter(ctx);
            setFailResponse(GateWayCodeEnum.TOKEN_VALID_FAIL);
        }
        return null;
    }

    /**
     * @param ctx
     * @return
     */
    private HttpGet buildHttpGet(RequestContext ctx) {
        HttpGet httpGet = new HttpGet(tokenValidUrl);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(2000)
                .setSocketTimeout(2000)
                .build();
        httpGet.setConfig(requestConfig);

        HttpServletRequest request = ctx.getRequest();
        String token = request.getHeader(Constants.RequestHeader.TOKEN);
        String appId = request.getHeader(Constants.RequestHeader.APP_ID);
        String accessId = request.getHeader(Constants.RequestHeader.ACCESS_ID);
        httpGet.setHeader(Constants.RequestHeader.TOKEN, token);
        httpGet.setHeader(Constants.RequestHeader.APP_ID, appId);
        httpGet.setHeader(Constants.RequestHeader.ACCESS_ID, accessId);
        httpGet.setHeader(Constants.RequestHeader.X_REQUEST_ID, requestId());

        Enumeration<String> headerNames =  request.getHeaderNames();
        while (headerNames != null && headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            if (!headerName.startsWith("X-")) {
                continue;
            }
            httpGet.setHeader(headerName, request.getHeader(headerName));
        }
        return httpGet;
    }


    private CloseableHttpClient buildHttpClient() {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        //将最大连接数增加到200
        cm.setMaxTotal(200);
        //将每个路由的默认最大连接数增加到20
        cm.setDefaultMaxPerRoute(20);
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
        return httpClient;
    }

    private boolean isNotNeedValidToken(RequestContext ctx) {
        ZhomeRouteDto zhomeRouteDto = (ZhomeRouteDto)ctx.get(Constants.RequestContextKey.CTX_X_ROUTEINFO);
        return zhomeRouteDto.getNeedToken() == 0;
    }
}
